package com.tencent.wxcloudrun.service.business.zuke;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tencent.wxcloudrun.config.CustomException;
import com.tencent.wxcloudrun.config.UserContext;
import com.tencent.wxcloudrun.pojo.bo.MediaInfo;
import com.tencent.wxcloudrun.pojo.bo.NoticeConstant;
import com.tencent.wxcloudrun.pojo.dto.resp.CurHouseDetailResp;
import com.tencent.wxcloudrun.pojo.dto.resp.GetHomeListResp;
import com.tencent.wxcloudrun.pojo.po.*;
import com.tencent.wxcloudrun.service.*;
import com.tencent.wxcloudrun.service.business.NoticeService;
import com.tencent.wxcloudrun.service.business.fangdong.HouseManageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CurHouseService {

    @Resource
    private XFeeManageMasterService xFeeManageMasterService;

    @Resource
    private XHouseInfoService xHouseInfoService;

    @Resource
    private XLeaseMiddleService xLeaseMiddleService;

    @Resource
    private XHelpmateInfoService xHelpmateInfoService;

    @Resource
    private XPersonInfoService xPersonInfoService;

    @Resource
    private NoticeService noticeService;

    @Resource
    private XTodoInfoService xTodoInfoService;

    public List<GetHomeListResp> getHomeList() {
        String openId = UserContext.getOpenId();
        LambdaQueryWrapper<XFeeManageMaster> xFeeManageMasterLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getTenantId, openId);
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getEffect, "yes");
        List<XFeeManageMaster> xFeeManageMasters = xFeeManageMasterService.list(xFeeManageMasterLambdaQueryWrapper);
        List<GetHomeListResp> respList = new ArrayList<>();
        if (CollUtil.isEmpty(xFeeManageMasters)) {
            return respList;
        }
        for (XFeeManageMaster manageMaster : xFeeManageMasters) {
            LambdaQueryWrapper<XHouseInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(XHouseInfo::getHouseId, manageMaster.getHouseId());
            XHouseInfo xHouseInfo = xHouseInfoService.getOne(queryWrapper);
            if (xHouseInfo == null) {
                continue;
            }
            GetHomeListResp getHomeListResp = new GetHomeListResp();
            getHomeListResp.setHouseName(xHouseInfo.getHouseName());
            getHomeListResp.setAddress(xHouseInfo.getAddress());
            getHomeListResp.setStatus(manageMaster.getCurStatus());
            if (xHouseInfo.getPicId() != null) {
                List<MediaInfo> mediaInfoList = JSON.parseArray(xHouseInfo.getPicId(), MediaInfo.class);
                List<MediaInfo> collect = mediaInfoList.stream()
                        .filter(var -> "jpeg".equalsIgnoreCase(HouseManageService.getLastPartAfterDot(var.getFileID())) ||
                                "jpg".equalsIgnoreCase(HouseManageService.getLastPartAfterDot(var.getFileID())) ||
                                "png".equalsIgnoreCase(HouseManageService.getLastPartAfterDot(var.getFileID()))).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(collect)) {
                    getHomeListResp.setPic(collect.get(0).getFileID());
                }
            }
            getHomeListResp.setHouseId(manageMaster.getHouseId());
            respList.add(getHomeListResp);
        }
        return respList;
    }

    public CurHouseDetailResp getHouseInfo(String houseId) {
        String openId = UserContext.getOpenId();
        LambdaQueryWrapper<XFeeManageMaster> xFeeManageMasterLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getTenantId, openId);
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getEffect, "yes");
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getHouseId, houseId);
        XFeeManageMaster xFeeManageMasters = xFeeManageMasterService.getOne(xFeeManageMasterLambdaQueryWrapper);
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, houseId);
        XHouseInfo oneByHouseId = xHouseInfoService.getOne(xHouseInfoLambdaQueryWrapper);
        CurHouseDetailResp curHouseDetailResp = new CurHouseDetailResp();
        curHouseDetailResp.setHouseId(houseId);
        curHouseDetailResp.setPicId(JSON.parseArray(oneByHouseId.getPicId(), MediaInfo.class));
        curHouseDetailResp.setMouthFee(xFeeManageMasters.getMouthFee().toPlainString());
        curHouseDetailResp.setManageFee(xFeeManageMasters.getManageFee().toPlainString());
        curHouseDetailResp.setDeposit(xFeeManageMasters.getDeposit().toPlainString());
        curHouseDetailResp.setWaterUnit(xFeeManageMasters.getWaterUnit().toPlainString());
        curHouseDetailResp.setPowerUnit(xFeeManageMasters.getPowerUnit().toPlainString());
        curHouseDetailResp.setGasUnit(xFeeManageMasters.getGasUnit().toPlainString());
        curHouseDetailResp.setQyDate(DateUtil.format(xFeeManageMasters.getCreateTime(), "yyyy-MM-dd"));
        curHouseDetailResp.setQyTime(xFeeManageMasters.getLiveNum() + " " + xFeeManageMasters.getLiveYmd());
        curHouseDetailResp.setQyFee(xFeeManageMasters.getFirstFee().toPlainString());
        curHouseDetailResp.setHouseStatus(xFeeManageMasters.getCurStatus());
        Date date = new Date();
        curHouseDetailResp.setLiveDay(String.valueOf(DateUtil.between(xFeeManageMasters.getCreateTime(), date, DateUnit.DAY)));
        DateTime endDate = null;
        if (xFeeManageMasters.getLiveYmd().equals("日")) {
            endDate = DateUtil.offsetDay(xFeeManageMasters.getCreateTime(), xFeeManageMasters.getLiveNum());
            curHouseDetailResp.setEndDate(DateUtil.format(endDate, "yyyy-MM-dd"));
        }
        if (xFeeManageMasters.getLiveYmd().equals("月")) {
            endDate = DateUtil.offsetMonth(xFeeManageMasters.getCreateTime(), xFeeManageMasters.getLiveNum());
            curHouseDetailResp.setEndDate(DateUtil.format(endDate, "yyyy-MM-dd"));
        }
        if (xFeeManageMasters.getLiveYmd().equals("年")) {
            endDate = DateUtil.offsetMonth(xFeeManageMasters.getCreateTime(), xFeeManageMasters.getLiveNum() * 12);
            curHouseDetailResp.setEndDate(DateUtil.format(endDate, "yyyy-MM-dd"));
        }
        Date nextPayDate = null;
        if (xFeeManageMasters.getRentType().equals("1")) { // 固定一月中的某天进行收租
            nextPayDate = guDingNextRentDate(xFeeManageMasters.getCreateTime(), date, xFeeManageMasters.getPayFeeDate());
            curHouseDetailResp.setNextPayDate(DateUtil.format(nextPayDate, "yyyy-MM-dd"));
        }
        if (xFeeManageMasters.getRentType().equals("0")) { // 以签约完成日为准，每30日一个周期进行收款。
            nextPayDate = for30NextRentDate(xFeeManageMasters.getCreateTime(), date);
            curHouseDetailResp.setNextPayDate(DateUtil.format(nextPayDate, "yyyy-MM-dd"));
        }
        // 如果下次付款是最后一期的情况
        if (DateUtil.compare(nextPayDate, endDate) >= 0) {
            long between = DateUtil.between(date, endDate, DateUnit.DAY);
            curHouseDetailResp.setNextPayDate("还剩" + between + "天到期");
        }
        return curHouseDetailResp;
    }

    public Date guDingNextRentDate(Date startDate, Date nowDate, String rentDayStr) {
        // 解析收租日字符串为整数
        int rentDay = Integer.parseInt(rentDayStr);
        // 转换为LocalDate（使用系统默认时区）
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate now = nowDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 确定计算基准日期（取当前日期和开始日期中较晚的一个）
        LocalDate baseDate = now.isAfter(start) ? now : start;
        // 构建基准日期所在月的收租日
        LocalDate rentDateThisMonth = LocalDate.of(baseDate.getYear(), baseDate.getMonth(), rentDay);
        // 计算下一个收租日
        LocalDate nextRentDate;
        if (baseDate.isAfter(rentDateThisMonth)) {
            // 如果基准日期已过本月收租日，则跳到下个月
            nextRentDate = rentDateThisMonth.plusMonths(1);
        } else {
            // 否则使用本月收租日
            nextRentDate = rentDateThisMonth;
        }
        // 转换为Date并返回
        return Date.from(nextRentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    public Date for30NextRentDate(Date contractDate, Date currentDate) {
        // 转换为Java 8的LocalDate类型（使用系统默认时区）
        LocalDate start = contractDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate now = currentDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 如果当前日期在签约日期之前，则下次收租日就是签约日期
        if (now.isBefore(start)) {
            return Date.from(start.atStartOfDay(ZoneId.systemDefault()).toInstant());
        }
        // 计算签约日到当前日的天数差
        long daysBetween = ChronoUnit.DAYS.between(start, now);
        // 计算完整周期数（每30天一个周期）
        long fullCycles = daysBetween / 30;
        // 计算下次收租日（当前周期结束后的下一个收租日）
        LocalDate nextRentDate = start.plusDays((fullCycles + 1) * 30);
        // 转换回java.util.Date类型
        return Date.from(nextRentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    @Transactional
    public String applyQuit(String houseId) {
        String openId = UserContext.getOpenId();
        Date date = new Date();
        LambdaQueryWrapper<XFeeManageMaster> xFeeManageMasterLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getHouseId, houseId);
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getTenantId, openId);
        xFeeManageMasterLambdaQueryWrapper.eq(XFeeManageMaster::getEffect, "yes");
        XFeeManageMaster one = xFeeManageMasterService.getOne(xFeeManageMasterLambdaQueryWrapper);

        // 获取房屋信息
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, houseId);
        XHouseInfo houseInfo = xHouseInfoService.getOne(xHouseInfoLambdaQueryWrapper);

        LambdaQueryWrapper<XLeaseMiddle> xLeaseMiddleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xLeaseMiddleLambdaQueryWrapper.eq(XLeaseMiddle::getHouseId, one.getHouseId());
        xLeaseMiddleLambdaQueryWrapper.eq(XLeaseMiddle::getTenantId, openId);
        List<XLeaseMiddle> list = xLeaseMiddleService.list(xLeaseMiddleLambdaQueryWrapper);
        if (CollUtil.isNotEmpty(list)) {
            throw new CustomException("该房屋已发起了退租，不可重复提交");
        }

        // 保存此时退租申请信息  某个租客在某个时候，对属于某房东的某个具体房屋发起了退租申请
        XLeaseMiddle xLeaseMiddle = new XLeaseMiddle();
        String snowflakeNextIdStr = IdUtil.getSnowflakeNextIdStr();
        xLeaseMiddle.setLeaseId(snowflakeNextIdStr);
        xLeaseMiddle.setHouseId(one.getHouseId());
        xLeaseMiddle.setTenantId(one.getTenantId());
        xLeaseMiddle.setLandId(one.getLandId());
        xLeaseMiddle.setFeeMasterId(one.getBusinessId());
        xLeaseMiddle.setCreateTime(date);
        xLeaseMiddleService.save(xLeaseMiddle);

        XTodoInfo xTodoInfoTanent = new XTodoInfo(); // 租客
        xTodoInfoTanent.setTodoId(IdUtil.getSnowflakeNextIdStr());
        xTodoInfoTanent.setTodoRole("tenant");
        xTodoInfoTanent.setTodoOption("退租申请");
        xTodoInfoTanent.setTodoPerson(openId);
        xTodoInfoTanent.setTodoThing(snowflakeNextIdStr);
        xTodoInfoTanent.setCreateTime(date);
        XTodoInfo xTodoInfoLand = new XTodoInfo(); // 房东
        xTodoInfoLand.setTodoId(IdUtil.getSnowflakeNextIdStr());
        xTodoInfoLand.setTodoRole("land");
        xTodoInfoLand.setTodoOption("退租申请");
        xTodoInfoLand.setTodoPerson(houseInfo.getLandlordId());
        xTodoInfoLand.setTodoThing(snowflakeNextIdStr);
        xTodoInfoLand.setCreateTime(date);
        ArrayList<XTodoInfo> xTodoInfos = CollUtil.newArrayList(xTodoInfoTanent, xTodoInfoLand);
        xTodoInfoService.saveBatch(xTodoInfos);

        // 发送退租申请通知信息
        // 检查这个房子是否有助理在管理
        LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getLandlordId, houseInfo.getLandlordId());
        xHelpmateInfoLambdaQueryWrapper.like(XHelpmateInfo::getHouseList, houseId);
        List<XHelpmateInfo> helpList = xHelpmateInfoService.list(xHelpmateInfoLambdaQueryWrapper);

        // 找出租客的个人信息
        LambdaQueryWrapper<XPersonInfo> xPersonInfoTenant = new LambdaQueryWrapper<>();
        xPersonInfoTenant.eq(XPersonInfo::getPersonId, openId);
        xPersonInfoTenant.eq(XPersonInfo::getPersonType, "tenant");
        XPersonInfo tenantInfo = xPersonInfoService.getOne(xPersonInfoTenant);

        int helpFlag = 0; // 0表示没有助理，1表示有助理
        if (CollUtil.isNotEmpty(helpList)) { // 表明这间房子有助理在管理，甚至可能有多个，给他们发送通知
            for (XHelpmateInfo xHelpmateInfo : helpList) {
                ++helpFlag;
                noticeService.createNoticeByOpenid(xHelpmateInfo.getHelpmateId(), "helpmate",
                        NoticeConstant.APPLY_QUIT_HELP_TITLE,
                        String.format(NoticeConstant.APPLY_QUIT_HELP_CONTENT,
                                tenantInfo.getCardName(), tenantInfo.getPhone()));
            }
        }

        // 给房东发送通知
        noticeService.createNoticeByOpenid(houseInfo.getLandlordId(), "land",
                NoticeConstant.APPLY_QUIT_LAND_TITLE,
                String.format(NoticeConstant.APPLY_QUIT_LAND_CONTENT,
                        tenantInfo.getCardName(),
                        tenantInfo.getPhone(),
                        (helpFlag == 0 ? "" : "，该信息已同步至助理")));

        // 给租客发送确认通知
        noticeService.createNoticeByOpenid(openId, "tenant",
                NoticeConstant.APPLY_QUIT_TENANT_TITLE,
                NoticeConstant.APPLY_QUIT_TENANT_CONTENT);

        return "success";
    }
}
